package com.ehotting.edsta.circuitDesign.gen.element;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.ehotting.edsta.circuitDesign.bean.AllMapBean;
import com.ehotting.edsta.circuitDesign.domain.EsCircuit;
import com.ehotting.edsta.circuitDesign.domain.EsCircuitCodeDataTemplate;
import com.ehotting.edsta.circuitDesign.domain.EsElement;
import com.ehotting.edsta.circuitDesign.domain.EsSceneParam;
import com.ehotting.edsta.circuitDesign.enums.CodeDataTypeEnum;
import com.ehotting.edsta.circuitDesign.gen.ScriptLogger;
import com.ehotting.edsta.circuitDesign.gen.element.bean.EsArrayList;
import com.ehotting.edsta.circuitDesign.gen.element.helper.ElementResultComposeHelper;
import com.ehotting.edsta.circuitDesign.gen.element.helper.ElementScriptHelper;
import com.ehotting.edsta.circuitDesign.groovy.Groovy;
import com.ehotting.edsta.circuitDesign.service.IEsCircuitCodeDataTemplateService;
import com.ehotting.edsta.circuitDesign.service.IEsCircuitService;
import com.ehotting.edsta.circuitDesign.service.IEsSceneParamService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/***
 * 元器件选择引擎
 */
@Component
public class ElementScriptEngine {


    private Logger logger = LoggerFactory.getLogger(ElementScriptEngine.class);

    @Autowired
    private ElementScriptFactory elementScriptFactory;
    @Autowired
    private Groovy groovy;
    @Autowired
    private ElementScriptHelper elementScriptHelper;
    @Autowired
    private IEsSceneParamService esSceneParamService;
    @Autowired
    private IEsCircuitService esCircuitService;
    @Autowired
    private IEsCircuitCodeDataTemplateService esCircuitCodeDataTemplateService;


    public Map<String, EsElement> invoke(Long sceneId, Map<String,Object> context, AllMapBean all){

        String script = genScript(sceneId);
        // 定义输出对象
        List<Map<String, Object>> outMapList = new EsArrayList<>();

        Object[] mainParam = runParam(sceneId,context, outMapList,all);
        ScriptLogger.info("ARGS:{}",JSON.toJSONString(mainParam, SerializerFeature.DisableCircularReferenceDetect));
        try {
            groovy.runGroovyScript(script, elementScriptHelper.genMainName(sceneId), mainParam);
        }catch (Exception e){
            e.printStackTrace();
            ScriptLogger.error(e,script,mainParam);
            return null;
        }

        logger.info("outMapList.size():{}",outMapList.size());
        List<String> outputElementKeyList =  esSceneParamService.findCodeListBySceneId(sceneId);
        logger.info("outputElementKeyList.size():{}",outputElementKeyList.size());
        Map<String,EsElement> resultMap = ElementResultComposeHelper.invoke(outMapList,outputElementKeyList);
        ScriptLogger.info("RESULT:{}",JSON.toJSONString(resultMap, SerializerFeature.DisableCircularReferenceDetect));

        return resultMap;
    }

    public String genScript(Long sceneId){
        // 输入参数 inputParamList，用户输入的参数，方法入参，用户可在代码快里面用这个参数
        List<EsCircuitCodeDataTemplate>  inputParamList =  getInputParamList(sceneId);
        // 输出参数 outputParamList，程序输出的参数，有多少个输出参数就有多少个循环方法
        List<EsSceneParam> outputParamList =  esSceneParamService.findBySceneId(sceneId);
        String methodBody = elementScriptFactory.genMethod(sceneId,inputParamList,outputParamList);
        String callBody = elementScriptFactory.genCallBySceneId( sceneId,  inputParamList);
        return elementScriptHelper.gen(sceneId,  methodBody, callBody,inputParamList,outputParamList);
    }

    private List<EsCircuitCodeDataTemplate>  getInputParamList(Long sceneId){
        EsCircuit circuit = esCircuitService.selectEsCircuitById(sceneId);
        List<EsCircuitCodeDataTemplate>  inputParamList =  esCircuitCodeDataTemplateService.selectByTypeAndCircuitTypeId(CodeDataTypeEnum.INPUT_PARAM,circuit.getCircuitTypeId());
        return inputParamList;
    }


    public String genByRuleScriptId(Long sceneId, Long scriptId){
        // 输入参数 inputParamList，用户输入的参数，方法入参，用户可在代码快里面用这个参数
        List<EsCircuitCodeDataTemplate> inputParamList = getInputParamList(sceneId);
        // 输出参数 outputParamList，程序输出的参数，有多少个输出参数就有多少个循环方法
        List<EsSceneParam> outputParamList =  esSceneParamService.findBySceneId(sceneId);

        String methodBody = elementScriptFactory.genMethodByRuleScriptId(scriptId,inputParamList,outputParamList);
        String callBody = elementScriptFactory.genCallByRuleScriptId(scriptId,   inputParamList);
        return elementScriptHelper.gen(sceneId, methodBody, callBody,inputParamList,outputParamList);
    }

    private Object[] runParam(Long sceneId,Map<String,Object> param,List<Map<String, Object>> outMapList,AllMapBean all){
        List<EsCircuitCodeDataTemplate> inputParamList =   getInputParamList( sceneId);
        // 定义脚本入参对象
        Object[] objectArr = new Object[inputParamList.size() + 2];
        for (int i = 0; i < inputParamList.size(); i++){
            objectArr[i] = param.get(inputParamList.get(i).getCode());
        }
        objectArr[objectArr.length - 2] = outMapList;
        objectArr[objectArr.length - 1 ] = all;
        return objectArr;
    }



    public List<Map<String, EsElement>> runByRuleScriptId(Long sceneId, Long scriptId, Map<String,Object> context,AllMapBean all){

        String script = genByRuleScriptId(sceneId,scriptId);
        // 定义输入对象
        List<Map<String, Object>> outMapList = new EsArrayList<>();
        // 定义脚本入参对象
        Object[] mainParam = runParam(sceneId,context, outMapList, all);

        ScriptLogger.info(JSON.toJSONString(mainParam, SerializerFeature.DisableCircularReferenceDetect));
        try {
            groovy.runGroovyScript(script, elementScriptHelper.genMainName(sceneId), mainParam);
        }catch (Exception e){
            e.printStackTrace();
            ScriptLogger.error(e,script,mainParam);
        }

        List<String> keyList =  esSceneParamService.findCodeListBySceneId(sceneId);
        List<Map<String, EsElement>> elementMap  = ElementResultComposeHelper.invoke4List(outMapList,keyList);

        return  elementMap;

    }

}